package com.nowcoder.topic.hash.middle;

import java.util.HashMap;

/**
 * NC223 从中序与后序遍历序列构造二叉树
 * @author d3y1
 */
public class NC223 {
    HashMap<Integer,Integer> inMap = new HashMap<>();

    /**
     * 代码中的类名、方法名、参数名已经指定，请勿修改，直接返回方法规定的值即可
     *
     * 相似 -> NC12 重建二叉树 [nowcoder]
     *
     * @param inorder int整型一维数组 中序遍历序列
     * @param postorder int整型一维数组 后序遍历序列
     * @return TreeNode类
     */
    public TreeNode buildTree (int[] inorder, int[] postorder) {
        // return solution1(inorder, postorder);
        return solution2(inorder, postorder);
    }

    /**
     * 哈希 + 递归
     *
     * 输入: [2,1,5,6,4,3],[2,6,5,4,3,1]
     * 输出: {1,2,3,#,#,4,#,5,#,#,6}
     *
     * @param inorder
     * @param postorder
     * @return
     */
    private TreeNode solution1(int[] inorder, int[] postorder){
        int n = inorder.length;
        if(n == 0){
            return null;
        }

        // 哈希: val -> idx
        for(int i=0; i<n; i++){
            inMap.put(inorder[i], i);
        }

        // 根结点
        TreeNode root = new TreeNode(postorder[n-1]);
        // 递归遍历
        dfs(postorder, root, 0, n-1, 0, n-1);

        return root;
    }

    /**
     * 递归遍历
     * @param postorder
     * @param root
     * @param inLeft
     * @param inRight
     * @param postLeft
     * @param postRight
     */
    private void dfs(int[] postorder, TreeNode root, int inLeft, int inRight, int postLeft, int postRight){
        int inRootIdx = inMap.get(root.val);

        int leftSize = inRootIdx-inLeft;
        int rightSize = inRight-inRootIdx;

        // 有左子树
        if(leftSize > 0){
            root.left = new TreeNode(postorder[postLeft+leftSize-1]);
            dfs(postorder, root.left, inLeft, inRootIdx-1, postLeft, postLeft+leftSize-1);
        }

        // 有右子树
        if(rightSize > 0){
            root.right = new TreeNode(postorder[postRight-1]);
            dfs(postorder, root.right, inRootIdx+1, inRight, postLeft+leftSize, postRight-1);
        }
    }

    //////////////////////////////////////////////////////////////////////////////////////

    // 后序遍历根结点索引
    private int postRootIdx;

    private TreeNode solution2(int[] inorder, int[] postorder){
        int n = postorder.length;
        postRootIdx = n-1;

        // 哈希: val -> idx
        for(int i=0; i<n; i++){
            inMap.put(inorder[i], i);
        }

        return build(postorder, 0, n-1);
    }

    /**
     * 递归遍历
     *
     * 二叉树后序遍历: 左 -> 右 -> 根
     * 可利用该性质直接找到后序遍历根节点, 子树遍历先右后左: 右 -> 左
     *
     * @param postorder
     * @param inLeft
     * @param inRight
     * @return
     */
    private TreeNode build(int[] postorder, int inLeft, int inRight){
        if(inLeft > inRight){
            return null;
        }

        // 根
        int postRootVal = postorder[postRootIdx--];
        TreeNode root = new TreeNode(postRootVal);

        if(inLeft == inRight){
            return root;
        }

        // 中序遍历根结点索引
        int inRootIdx = inMap.get(postRootVal);

        // 右
        root.right = build(postorder, inRootIdx+1, inRight);
        // 左
        root.left = build(postorder, inLeft, inRootIdx-1);

        return root;
    }

    private static class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;
        }
    }
}